"""
统一记忆管理器

功能：
- 统一管理所有类型的记忆（对话、分析历史、实体）
- 提供上下文聚合功能
- 提供便捷的记忆访问接口
- 单例模式确保全局唯一

作者：System
创建时间：2025-01-13
"""

from typing import Dict, List, Optional
import re
from memory.conversation_memory import ConversationMemory
from memory.analysis_history import AnalysisHistory
from memory.entity_memory import EntityMemory


class MemoryManager:
    """统一记忆管理器"""
    
    _instance = None
    
    def __new__(cls):
        """单例模式"""
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance
    
    def __init__(self):
        """初始化记忆管理器"""
        if self._initialized:
            return
        
        # 初始化三个记忆组件
        self.conversation = ConversationMemory()
        self.analysis_history = AnalysisHistory()
        self.entities = EntityMemory()
        
        self._initialized = True
    
    def get_context_for_query(self, thread_id: str, query: str, max_context_length: int = 500) -> str:
        """
        获取查询的上下文信息
        
        Args:
            thread_id: 会话线程ID
            query: 用户查询内容
            max_context_length: 每个上下文片段的最大长度
            
        Returns:
            聚合的上下文字符串
        """
        context_parts = []
        
        # 1. 添加对话历史摘要
        conv_summary = self.conversation.get_conversation_summary(thread_id, max_length=100)
        if conv_summary:
            context_parts.append("=== 对话历史 ===")
            context_parts.append(conv_summary)
        
        # 2. 提取查询中的债券代码并添加相关信息
        bond_codes = self._extract_bond_codes(query)
        
        if bond_codes:
            context_parts.append("\n=== 相关债券信息 ===")
            
            for code in bond_codes[:3]:  # 最多处理3个债券代码
                # 获取历史分析
                latest_analysis = self.analysis_history.get_latest_analysis(code)
                if latest_analysis:
                    analysis_type = latest_analysis.get("type", "未知")
                    context_parts.append(f"债券 {code} - 最近分析类型: {analysis_type}")
                
                # 获取实体信息
                entity = self.entities.get_bond_info(code)
                if entity and entity.get("info"):
                    bond_name = entity["info"].get("bond_nm", "N/A")
                    issuer = entity["info"].get("issuer_nm", "N/A")
                    context_parts.append(f"债券 {code} - {bond_name} (发行人: {issuer})")
        
        # 3. 提取查询中的公司名称（简单匹配）
        company_names = self._extract_company_names(query)
        if company_names:
            context_parts.append("\n=== 相关公司信息 ===")
            for company in company_names[:2]:  # 最多处理2个公司
                entity = self.entities.get_company_info(company)
                if entity and entity.get("info"):
                    context_parts.append(f"公司 {company}: {str(entity['info'])[:100]}...")
        
        # 组合上下文
        full_context = "\n".join(context_parts)
        
        # 限制总长度
        if len(full_context) > max_context_length * 3:
            full_context = full_context[:max_context_length * 3] + "..."
        
        return full_context if context_parts else ""
    
    def _extract_bond_codes(self, text: str) -> List[str]:
        """
        从文本中提取债券代码
        
        Args:
            text: 输入文本
            
        Returns:
            债券代码列表
        """
        # 匹配6位数字的债券代码
        codes = re.findall(r'\b\d{6}\b', text)
        # 去重并保持顺序
        seen = set()
        unique_codes = []
        for code in codes:
            if code not in seen:
                seen.add(code)
                unique_codes.append(code)
        return unique_codes
    
    def _extract_company_names(self, text: str) -> List[str]:
        """
        从文本中提取公司名称（简单实现）
        
        Args:
            text: 输入文本
            
        Returns:
            可能的公司名称列表
        """
        # 这里可以使用更复杂的NER或关键词匹配
        # 简单实现：查找已知的公司实体
        company_names = []
        all_companies = self.entities.get_all_companies()
        
        for company_entity in all_companies:
            company_name = company_entity.get("name", "")
            if company_name and company_name in text:
                company_names.append(company_name)
        
        return company_names
    
    def save_analysis_result(
        self,
        bond_code: str,
        analysis_type: str,
        result: dict,
        thread_id: Optional[str] = None
    ) -> None:
        """
        保存分析结果到记忆系统
        
        Args:
            bond_code: 债券代码
            analysis_type: 分析类型
            result: 分析结果字典
            thread_id: 会话线程ID（可选）
        """
        # 1. 保存到分析历史
        self.analysis_history.add_analysis(bond_code, analysis_type, result, thread_id)
        
        # 2. 更新债券实体信息
        if "bond_info" in result:
            self.entities.add_or_update_bond(bond_code, result["bond_info"])
        
        # 3. 更新公司实体信息
        if "company_info" in result:
            company_name = result["company_info"].get("name")
            if company_name:
                self.entities.add_or_update_company(company_name, result["company_info"])
        
        # 4. 如果结果中有发行人信息，也更新到实体
        if "issuer_info" in result:
            issuer_name = result["issuer_info"].get("name")
            if issuer_name:
                self.entities.add_or_update_company(issuer_name, result["issuer_info"])
    
    def record_conversation(self, thread_id: str, user_message: str, assistant_response: str) -> None:
        """
        记录对话
        
        Args:
            thread_id: 会话线程ID
            user_message: 用户消息
            assistant_response: 助手回复
        """
        self.conversation.add_message(thread_id, "user", user_message)
        self.conversation.add_message(thread_id, "assistant", assistant_response)
    
    def get_bond_context(self, bond_code: str) -> Dict:
        """
        获取债券的完整上下文信息
        
        Args:
            bond_code: 债券代码
            
        Returns:
            包含实体信息和分析历史的字典
        """
        return {
            "entity_info": self.entities.get_bond_info(bond_code),
            "latest_analysis": self.analysis_history.get_latest_analysis(bond_code),
            "analysis_count": self.analysis_history.get_analysis_count(bond_code),
            "all_analyses": self.analysis_history.get_all_analyses(bond_code)[:5]
        }
    
    def clear_thread_conversation(self, thread_id: str) -> None:
        """
        清空指定线程的对话历史
        
        Args:
            thread_id: 会话线程ID
        """
        self.conversation.clear_conversation(thread_id)
    
    def clear_all(self) -> None:
        """清空所有记忆（慎用！）"""
        self.conversation.clear_all_conversations()
        self.analysis_history = AnalysisHistory()
        self.entities = EntityMemory()
    
    def get_statistics(self) -> Dict:
        """
        获取记忆系统的统计信息
        
        Returns:
            包含各类统计信息的字典
        """
        conv_stats = self.conversation.get_statistics()
        analysis_stats = self.analysis_history.get_statistics()
        entity_stats = self.entities.get_statistics()
        
        return {
            "conversation": conv_stats,
            "analysis": analysis_stats,
            "entities": entity_stats,
            "summary": {
                "total_threads": conv_stats["total_threads"],
                "total_messages": conv_stats["total_messages"],
                "total_analyses": analysis_stats["total_analyses"],
                "total_bonds_analyzed": analysis_stats["total_bonds"],
                "total_entities": entity_stats["total_entities"]
            }
        }
    
    def get_frequently_analyzed_bonds(self, top_n: int = 10) -> List[tuple]:
        """
        获取分析次数最多的债券
        
        Args:
            top_n: 返回前N个债券
            
        Returns:
            [(bond_code, count), ...] 列表
        """
        return self.analysis_history.get_frequently_analyzed_bonds(top_n)
    
    def search_memory(self, keyword: str, search_type: str = "all") -> Dict:
        """
        在记忆系统中搜索关键词
        
        Args:
            keyword: 搜索关键词
            search_type: 搜索类型 ("all", "entities", "analyses")
            
        Returns:
            搜索结果字典
        """
        results = {}
        
        if search_type in ["all", "entities"]:
            results["entities"] = self.entities.search_entities(keyword)
        
        if search_type in ["all", "analyses"]:
            results["analyses"] = self.analysis_history.search_analyses(keyword)
        
        return results
    
    def cleanup_old_data(self, conversation_days: int = 30, analysis_days: int = 90, entity_days: int = 180) -> Dict:
        """
        清理过期数据
        
        Args:
            conversation_days: 对话保留天数
            analysis_days: 分析历史保留天数
            entity_days: 实体信息保留天数
            
        Returns:
            清理统计信息
        """
        # 注意：对话记忆没有基于时间的清理方法，这里跳过
        # 可以根据需要添加到 ConversationMemory
        
        analyses_cleared = self.analysis_history.clear_old_records(analysis_days)
        entities_cleared = self.entities.clear_old_entities(entity_days)
        
        return {
            "analyses_cleared": analyses_cleared,
            "entities_cleared": entities_cleared
        }
    
    def export_memory_snapshot(self) -> Dict:
        """
        导出记忆快照（用于备份或调试）
        
        Returns:
            包含所有记忆数据的字典
        """
        return {
            "conversations": self.conversation.conversations,
            "analysis_history": self.analysis_history.history,
            "entities": self.entities.entities,
            "timestamp": self._get_timestamp()
        }
    
    def _get_timestamp(self) -> str:
        """获取当前时间戳"""
        from datetime import datetime
        return datetime.now().isoformat()


# 创建全局单例实例
memory_manager = MemoryManager()


def get_memory_manager() -> MemoryManager:
    """
    获取全局记忆管理器单例
    
    Returns:
        MemoryManager实例
    """
    return memory_manager